package com.example.selflearning.service.ehcache;
import com.example.selflearning.entity.UserEntity;
import lombok.extern.slf4j.Slf4j;
import org.ehcache.ValueSupplier;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.ehcache.core.Ehcache;
import org.ehcache.expiry.Duration;
import org.ehcache.expiry.Expiry;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
/**
 * Created by yangjingzhi on 2019/5/20.
 */
@Slf4j
public class CustomExpiryCacheAsideUserService {
    private static final UserEntity NULL_USER = new UserEntity.NullUser();
    private Ehcache<String, UserEntity> cache;

    public CustomExpiryCacheAsideUserService() {
        cache = (Ehcache<String, UserEntity>) UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, UserEntity.class)
                .withExpiry(new CustomUserExpiry(new Duration(20, TimeUnit.SECONDS))).build(true);
    }

    public UserEntity findUser(String id) {
        UserEntity cached = cache.get(id);
        if (cached != null) {
            System.out.println("get user from cache: " + id);
            return cached;
        }
        UserEntity user = null;
        if (!id.equals("0")) {
            user = new UserEntity(id, "info ..."); // find user
        }
        System.out.println("get user from db: " + id);
        if (user == null) {
            user = NULL_USER;
        }
        cache.put(id, user);
        return user;
    }

    public static void main(String[] args) throws Exception {
        final CustomExpiryCacheAsideUserService service = new CustomExpiryCacheAsideUserService();
        for (int i = 0; i < 5; i++) {
            service.findUser("" + i);
        }
        log.info("catch is  {}", service.cache);
        for (int i = 0; i < 10; i++) {
            /*service.cache.forEach(e -> {
                log.info(e.getKey());
            });*/
            service.cache.get("1");
            Thread.sleep(5000);
            log.info("===================");
        }
    }

    private static class CustomUserExpiry implements Expiry<String, UserEntity> {
        private final Duration ttl;

        public CustomUserExpiry(Duration ttl) {
            this.ttl = ttl;
        }

        @Override
        public Duration getExpiryForCreation(String key, UserEntity userEntity) {
            if (userEntity.isNull()) {
                System.out.println("user is null: " + key);
                return new Duration(10, TimeUnit.SECONDS);
            }
            long length = ttl.getLength();
            if (length > 10) {
                long max = length / 2;
                long random = ThreadLocalRandom.current().nextLong(-max, max);

                return new Duration(ttl.getLength() + random, ttl.getTimeUnit());
            }
            return ttl;
        }

        @Override
        public Duration getExpiryForAccess(String s, ValueSupplier<? extends UserEntity> valueSupplier) {
            return null;
        }

        @Override
        public Duration getExpiryForUpdate(String s, ValueSupplier<? extends UserEntity> valueSupplier, UserEntity userEntity) {
            return ttl;
        }
    }
}
